//package com.njcky.service;
//
//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.core.type.TypeReference;
//import com.fasterxml.jackson.databind.JsonNode;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.njcky.model.dto.QueryPipelineLengthDTO;
//import com.njcky.utils.db.DBPool2DataSourceUtil;
//import com.njcky.utils.page.StringUtils;
//import com.njcky.utils.page.entity.TableDataInfo;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//import org.springframework.util.ObjectUtils;
//
//import java.math.BigDecimal;
//import java.util.*;
//
///**
// * 连通性分析和距离实现服务
// */
//
//@Service
//public class ConnectivityDistanceAnalysis {
//
//
//    private static final ObjectMapper objectMapper = new ObjectMapper();
//
//
//    @Autowired
//    DBPool2DataSourceUtil pool2DataSourceUtil;
//
//
//    /**
//     * 连通性分析数据
//     *
//     * @param dto
//     * @return
//     */
//    public TableDataInfo connectivityPublic(QueryPipelineLengthDTO dto) {
//        // 分别执行两次
//        String firstPoslon = dto.getFirstPoslon();
//        String firstPoslat = dto.getFirstPoslat();
//        String endPoslon = dto.getEndPoslon();
//        String endPoslat = dto.getEndPoslat();
//        String tableName = dto.getTables().get(0);
//        int pageSize = dto.getPageSize();
//        int pageNum = dto.getPageNum();
//        Map<String, Object> objectOneMap = connectivityOnePoint(firstPoslon, firstPoslat, tableName);
//        if (ObjectUtils.isEmpty(objectOneMap)) {
//            return null;
//        }
//        Map<String, Object> objectTwoMap = connectivityOnePoint(endPoslon, endPoslat, tableName);
//        if (ObjectUtils.isEmpty(objectTwoMap)) {
//            return null;
//        }
//        String source = objectOneMap.get("source").toString();
//        String target = objectTwoMap.get("source").toString();
//        List<Map<String, Object>> mapList = connectivityTwoPoint(source, target, tableName, pageSize, pageNum);
//        if (ObjectUtils.isEmpty(mapList)) {
//            return null;
//        }
//
//        // 处理shapetext格式转换
//        for (Map<String, Object> map : mapList) {
//            if (map.containsKey("shapetext")) {
//                String originalShape = map.get("shapetext").toString();
//                String convertedShape = convertShapeText(originalShape);
//                map.put("shapetext", convertedShape);
//            }
//        }
//
//        TableDataInfo dataInfo = new TableDataInfo();
//        dataInfo.setCode(200);
//        dataInfo.setMsg("查询成功！");
//        dataInfo.setTotal(Long.parseLong(mapList.get(0).get("total").toString()));
//        dataInfo.setData(mapList);
//        return dataInfo;
//    }
//
//    /**
//     * 将MULTILINESTRING转换为LINESTRING并处理坐标
//     */
//    private String convertShapeText(String original) {
//        String lineString = original.replace("MULTILINESTRING", "LINESTRING");
//        lineString = lineString.replace("((", "(").replace("))", ")");
//        return lineString;
//    }
//
//    // 根据输入的起点获取相关的数据集
//    public Map<String, Object> connectivityOnePoint(String lon, String lat, String tableName) {
//        String sql = "SELECT " +
//                "gid, target, source," +
//                "ST_Distance(" +
//                "   ST_Transform(ST_SetSRID(ST_MakePoint(" + lon + ", " + lat + "), 4326), 4549)," +
//                "   geom " +
//                ") AS distancea," +
//                "geom " +
//                "FROM " + tableName + " " +
//                "ORDER BY " +
//                "distancea " +
//                "LIMIT 1;";
//        Map<String, Object> objectMap = pool2DataSourceUtil.NpgNormal_GetListDicNo1(sql);
//        return objectMap;
//    }
//
//    public List<Map<String, Object>> connectivityTwoPoint(
//            String source,
//            String target,
//            String tableName,
//            Integer pageSize,  // 改为Integer包装类，支持null
//            Integer pageNum     // 改为Integer包装类，支持null
//    ) {
//        // 构建基础SQL
//        StringBuilder sqlBuilder = new StringBuilder();
//        sqlBuilder.append("SELECT ")
//                .append("a.*, ")
//                .append("a.xzq as ssqy, ")
//                .append("a.zydw as tcdw, ")
//                .append("st_astext(st_transform(a.geom, 4490)) as shapetext, ")
//                .append("(SELECT COUNT(*) FROM ").append(tableName).append(" a2, ")  // 总记录数子查询
//                .append("   (SELECT * FROM pgr_dijkstra ( ")
//                .append("       'SELECT gid AS id, source::integer, target::integer, length::double precision AS cost FROM ").append(tableName).append("', ")
//                .append(source).append(", ").append(target).append(", FALSE, FALSE")
//                .append("   )) T2 ")
//                .append("WHERE a2.gid = T2.id2) as total  ")
//                .append("FROM ")
//                .append(tableName).append(" a, ")
//                .append("(SELECT * FROM pgr_dijkstra ( ")
//                .append("   'SELECT gid AS id, source::integer, target::integer, length::double precision AS cost FROM ").append(tableName).append("', ")
//                .append(source).append(", ").append(target).append(", FALSE, FALSE")
//                .append(") ) T ")
//                .append("WHERE ")
//                .append("a.gid = T.id2 ");
//
//        // 动态添加分页条件（仅当pageSize和pageNum都不为null时）
//        if (pageSize != null && pageNum != null && pageSize > 0 && pageNum > 0) {
//            int offset = (pageNum - 1) * pageSize;
//            sqlBuilder.append("LIMIT ").append(pageSize).append(" OFFSET ").append(offset);
//        }
//        // 转换为最终SQL字符串
//        String sql = sqlBuilder.toString();
//        // 执行查询（需先校验参数安全性）
//        List<Map<String, Object>> connectivity = pool2DataSourceUtil.NpgNormal_GetListDic_getBsmDateParallel(sql);
//        return connectivity;
//    }
//
//
//    /**
//     * 连通性分析返回参数转换 （connectivity）
//     * TODO 工具
//     *
//     * @param rawDataList
//     * @return
//     */
//    public List<Map<String, Object>> processDataFromTableData(List<?> rawDataList) {
//        // 空列表处理
//        if (rawDataList == null || rawDataList.isEmpty()) {
//            return new ArrayList<>();
//        }
//        // 转换为List<Map<String, Object>>
//        List<Map<String, Object>> mapList = new ArrayList<>(rawDataList.size());
//        for (Object item : rawDataList) {
//            // 确保元素是Map类型，否则跳过（或根据实际类型处理）
//            if (item instanceof Map<?, ?>) {
//                // 强制转换为Map<String, Object>
//                @SuppressWarnings("unchecked")
//                Map<String, Object> dataMap = (Map<String, Object>) item;
//                mapList.add(dataMap);
//            } else {
//                // 非Map类型的处理（根据实际业务需求调整）
//                System.out.println("跳过非Map类型的元素: " + item.getClass());
//            }
//        }
//        // 调用原processResultList方法处理
//        return processResultList(mapList);
//    }
//
//
//    /**
//     * TODO 工具
//     * 处理结果列表：转换数值类型，保留特殊字符串（如时间戳）
//     */
//    public List<Map<String, Object>> processResultList(List<Map<String, Object>> resultList) {
//        List<Map<String, Object>> processedList = new ArrayList<>(resultList.size()); // 预设容量
//        for (Map<String, Object> item : resultList) {
//            Map<String, Object> processedItem = new HashMap<>(item.size()); // 预设容量
//            for (Map.Entry<String, Object> entry : item.entrySet()) {
//                String key = entry.getKey();
//                Object value = entry.getValue();
//                if (value == null) {
//                    processedItem.put(key, null);
//                    continue;
//                }
//                String strValue = value.toString().trim();
//                // 保留空字符串
//                if (strValue.isEmpty()) {
//                    processedItem.put(key, strValue);
//                    continue;
//                }
//                // 核心逻辑：特殊字段保持String类型
//                if (isPreserveAsString(key, strValue)) {
//                    processedItem.put(key, escapeSpecialChars(strValue)); // 安全转义
//                }
//                // 数值类型转换 - 统一转为BigDecimal避免溢出
//                else if (isNumeric(strValue)) {
//                    try {
//                        processedItem.put(key, new BigDecimal(strValue));
//                    } catch (NumberFormatException e) {
//                        processedItem.put(key, strValue);
//                    }
//                }
//                // 其他字段保持String并转义
//                else {
//                    processedItem.put(key, escapeSpecialChars(strValue));
//                }
//            }
//            processedList.add(processedItem);
//        }
//        return processedList;
//    }
//
//    /**
//     * TODO 工具
//     * 判断是否需要保持为String类型
//     * 1. 时间戳字段（如starttime）
//     * 2. 类似"20220507025410104"的17位数字字符串（时间格式）
//     */
//    private boolean isPreserveAsString(String key, String value) {
//        // 时间相关字段集合（使用Java 8支持的HashSet初始化）
//        Set<String> timeFields = new HashSet<>(Arrays.asList(
//                "starttime", "endtime", "gxsj", "inserttime",
//                "fqsj", "deletetime", "tcrq"
//        ));
//        if (timeFields.contains(key)) {
//            return true;
//        }
//        // 格式匹配：17位数字（如20220507025410104）
//        if (value.matches("^\\d{17}$")) {
//            return true;
//        }
//        return false;
//    }
//
//    /**
//     * TODO 工具
//     * 判断是否为数字（整数或小数）
//     */
//    private boolean isNumeric(String value) {
//        return value.matches("^[-+]?\\d+$") || value.matches("^[-+]?\\d+\\.\\d+$");
//    }
//
//    /**
//     * TODO 工具
//     * 转义特殊字符，防止XSS攻击
//     */
//    private String escapeSpecialChars(String value) {
//        if (value == null) {
//            return null;
//        }
//        return value.replaceAll("&", "&amp;")
//                .replaceAll("<", "&lt;")
//                .replaceAll(">", "&gt;")
//                .replaceAll("\"", "&quot;")
//                .replaceAll("'", "&#39;");
//    }
//
//
//    /**************************************************【下面是管线距离计算】***************************************************/
//
//    // 对geojson的结果进行转义
//    public Map<String, Object> getGeoJson(Map<String, Object> objectMapGeoJson) {
//        if (objectMapGeoJson == null || !objectMapGeoJson.containsKey("complete_geojson")) {
//            return new HashMap<>();
//        }
//        String json = objectMapGeoJson.get("complete_geojson").toString();
//        try {
//            return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {
//            });
//        } catch (Exception e) {
//            e.printStackTrace();
//            return new HashMap<>();
//        }
//    }
//
//    public Map<String, Object> queryPipelineLength(QueryPipelineLengthDTO dto) {
//        // 1. 校验入参非空
//        if (dto == null || dto.getTables() == null || dto.getTables().isEmpty()) {
//            return Collections.singletonMap("error", "入参DTO或表名不能为空");
//        }
//        String tableName = dto.getTables().get(0);
//        String firstPoslon = dto.getFirstPoslon();
//        String firstPoslat = dto.getFirstPoslat();
//        String endPoslon = dto.getEndPoslon();
//        String endPoslat = dto.getEndPoslat();
//        // 校验经纬度参数非空
//        if (StringUtils.isEmpty(firstPoslon) || StringUtils.isEmpty(firstPoslat)
//                || StringUtils.isEmpty(endPoslon) || StringUtils.isEmpty(endPoslat)) {
//            return Collections.singletonMap("error", "起点或终点经纬度不能为空");
//        }
//
//        // 2. 查询起点和终点信息
//        Map<String, Object> objectOneMap = point(firstPoslon, firstPoslat, tableName);
//        if (ObjectUtils.isEmpty(objectOneMap)) {
//            return Collections.singletonMap("error", "未查询到起点关联数据");
//        }
//
//        Map<String, Object> objectTwoMap = point(endPoslon, endPoslat, tableName);
//        // 修复原逻辑错误：此处应判断objectTwoMap而非objectOneMap
//        if (ObjectUtils.isEmpty(objectTwoMap)) {
//            return Collections.singletonMap("error", "未查询到终点关联数据");
//        }
//
//        // 3. 安全获取坐标和关联标识（避免null.toString()异常）
//        String firstX = String.valueOf(objectOneMap.getOrDefault("x", ""));
//        String firstY = String.valueOf(objectOneMap.getOrDefault("y", ""));
//        String firstSource = String.valueOf(objectOneMap.getOrDefault("source", ""));
//        String endX = String.valueOf(objectTwoMap.getOrDefault("x", ""));
//        String endY = String.valueOf(objectTwoMap.getOrDefault("y", ""));
//        String endTarget = String.valueOf(objectTwoMap.getOrDefault("target", ""));
//        // 校验关键标识非空
//        if (StringUtils.isEmpty(firstSource) || StringUtils.isEmpty(endTarget)) {
//            return Collections.singletonMap("error", "起点source或终点target为空");
//        }
//        // 4. 查询GeoJSON数据并校验
//        Map<String, Object> objectMap = jsonList(firstSource, endTarget, tableName);
//        if (ObjectUtils.isEmpty(objectMap) || !objectMap.containsKey("complete_geojson")) {
//            return Collections.singletonMap("error", "未查询到完整的GeoJSON数据");
//        }
//        // 5. 解析坐标并计算管线长度
//        String json = String.valueOf(objectMap.get("complete_geojson"));
//        String coordinateList = extractCoordinates(json); // 假设extractCoordinates已实现非空处理
//        // 校验坐标列表非空
//        if (StringUtils.isEmpty(coordinateList)) {
//            return Collections.singletonMap("error", "提取坐标列表失败");
//        }
//        Map<String, Object> pipeLineLength = pipeLineLength(firstX, firstY, endX, endY, coordinateList);
//        // 6. 处理GeoJSON（添加起点和终点）
//        Map<String, Object> geoJsonData;
//        try {
//            geoJsonData = getGeoJson(objectMap);
//        } catch (NumberFormatException e) {
//            return Collections.singletonMap("error", "经纬度格式错误，无法转换为数字：" + e.getMessage());
//        }
//        // 7. 组装返回结果
//        Map<String, Object> result = new HashMap<>();
//        result.put("pipelength", pipeLineLength.getOrDefault("segment_length_meters", 0));
//        result.put("geoJsonData", geoJsonData);
//        // 修复日志占位符使用错误
//        System.out.printf("处理后的geoJsonData：%s%n", geoJsonData);
//        return result;
//    }
//
//
//    //提取二维坐标的工具
//    public String extractCoordinates(String json) {
//        // 初始化Jackson的ObjectMapper
//        ObjectMapper objectMapper = new ObjectMapper();
//        // 解析JSON字符串为JsonNode
//        JsonNode rootNode = null;
//        try {
//            rootNode = objectMapper.readTree(json);
//        } catch (JsonProcessingException e) {
//            throw new RuntimeException(e);
//        }
//
//        // 分步获取节点并增加非空判断
//        // 1. 获取features节点
//        JsonNode featuresNode = rootNode.get("features");
//        if (featuresNode == null || !featuresNode.isArray() || featuresNode.isEmpty()) {
//            System.out.println("features节点不存在或为空数组");
//            return "";
//        }
//
//        // 2. 获取features[0]节点
//        JsonNode firstFeatureNode = featuresNode.get(0);
//        if (firstFeatureNode == null) {
//            System.out.println("features数组第一个元素为空");
//            return "";
//        }
//
//        // 3. 获取geometry节点（增加非空判断）
//        JsonNode geometryNode = firstFeatureNode.get("geometry");
//        if (geometryNode == null) {
//            System.out.println("geometry节点为空");
//            return "";
//        }
//
//        // 4. 获取coordinates节点
//        JsonNode coordinatesNode = geometryNode.get("coordinates");
//        if (coordinatesNode == null || !coordinatesNode.isArray()) {
//            System.out.println("coordinates节点不存在或不是数组");
//            return "";
//        }
//
//        // 提取坐标并格式化
//        List<String> coordinateList = new ArrayList<>();
//        for (JsonNode coord : coordinatesNode) {
//            // 每个坐标是 [经度, 纬度] 数组，增加对坐标数组的有效性判断
//            if (coord != null && coord.isArray() && coord.size() >= 2) {
//                double lon = coord.get(0).asDouble();  // 经度
//                double lat = coord.get(1).asDouble();  // 纬度
//                coordinateList.add(lon + " " + lat);
//            } else {
//                System.out.println("无效的坐标格式：" + coord);
//            }
//        }
//
//        System.out.println("得到整个所有二维数组的数据：" + coordinateList);
//        return String.join(",", coordinateList);
//    }
//
//
//    // 第一步，获取坐标的X,Y
//    public Map<String, Object> point(String lon, String lat, String tableName) {
//        String sql = "WITH fixed_point AS (\n" +
//                "  SELECT ST_Transform(ST_SetSRID(ST_MakePoint( " + lon + ", " + lat + "), 4326), 4549) AS point_geom\n" +
//                "),\n" +
//                "exploded_lines AS (\n" +
//                "  SELECT \n" +
//                "    gid,\n" +
//                "    target,\n" +
//                "    \"source\",\n" +
//                "    (ST_Dump(geom)).geom AS line_geom,  \n" +
//                "    geom AS original_multi_geom       \n" +
//                "  FROM  " + tableName + "\n" +
//                "  WHERE ST_GeometryType(geom) = 'ST_MultiLineString'\n" +
//                "),\n" +
//                "projection_data AS (\n" +
//                "  SELECT \n" +
//                "    gid,\n" +
//                "    target,\n" +
//                "    \"source\",\n" +
//                "    ST_Distance(fp.point_geom, el.line_geom) AS distancea,\n" +
//                "    el.original_multi_geom AS original_geom,\n" +
//                "    ST_LineInterpolatePoint(el.line_geom, ST_LineLocatePoint(el.line_geom, fp.point_geom)) AS projection_geom\n" +
//                "  FROM exploded_lines el, fixed_point fp\n" +
//                ")\n" +
//                "SELECT \n" +
//                "  gid,\n" +
//                "  target,\n" +
//                "  \"source\",\n" +
//                "  ST_X(st_transform(projection_geom, 4490)) AS x, \n" +
//                "  ST_Y(st_transform(projection_geom, 4490)) AS y\n" +
//                "FROM projection_data\n" +
//                "ORDER BY distancea\n" +
//                "LIMIT 1;";
//        Map<String, Object> objectMap = pool2DataSourceUtil.NpgNormal_GetListDicNo1(sql);
//        return objectMap;
//    }
//
//    // 从返回的json中构造结构去取数据，二维数组，经纬度之间是空格，
//    public Map<String, Object> jsonList(String source, String target, String tableName) {
//        // 美化SQL结构：使用缩进分层，为source和target添加单引号
//        String sql =
//                "SELECT row_to_json(featcoll) AS complete_geojson " +
//                        "FROM ( " +
//                        "SELECT " +
//                        "'FeatureCollection' AS type, " +
//                        "array_to_json(array_agg(row_to_json(feat))) AS features " +
//                        "FROM ( " +
//                        "SELECT " +
//                        "'Feature' AS type, " +
//                        "ST_AsGeoJSON(st_transform(final_path.path_geometry, 4490))::text::json AS geometry " +
//                        "FROM ( " +
//                        "WITH path_edges AS ( " +
//                        "SELECT " +
//                        "P.seq, " +
//                        "e.geom " +
//                        "FROM " +
//                        "pgr_dijkstra( " +
//                        "'SELECT gid AS id, source, target, length AS cost FROM " + tableName + "', " +
//                        "'" + source + "', '" + target + "', FALSE, FALSE " +
//                        ") P " +
//                        "JOIN " + tableName + " e ON P.id2 = e.gid " +
//                        "WHERE " +
//                        "P.id2 != -1 " +
//                        "ORDER BY " +
//                        "P.seq " +
//                        ") " +
//                        "SELECT " +
//                        "ST_LineMerge(ST_Union(geom ORDER BY seq)) AS path_geometry " +
//                        "FROM " +
//                        "path_edges " +
//                        ") final_path " +
//                        ") AS feat " +
//                        ") AS featcoll;";
//
//        Map<String, Object> json = pool2DataSourceUtil.NpgNormal_GetListDicNo1(sql);
//        return json;
//    }
//
//
//    // 计算距离
//    public Map<String, Object> pipeLineLength(String firstX, String firstY, String endX, String endY, String coordinateList) {
//        // 移除所有\n，修正ST_SetSRID后的多余逗号，保持缩进结构
//        String sql =
//                "WITH line_data AS ( " +
//                        "SELECT ST_GeomFromText( " +
//                        "'LINESTRING(" + coordinateList + ")', 4326 " +
//                        ") AS line_geom " +
//                        "), points AS ( " +
//                        "SELECT " +
//                        "ST_SetSRID(ST_MakePoint(" + firstX + ", " + firstY + "), 4326) AS point1, " +  // 修正此处语法
//                        "ST_SetSRID(ST_MakePoint(" + endX + ", " + endY + "), 4326) AS point2 " +  // 移除了多余的逗号
//                        "), line_info AS ( " +
//                        "SELECT " +
//                        "ST_LineLocatePoint(ld.line_geom, p.point1) AS loc1, " +
//                        "ST_LineLocatePoint(ld.line_geom, p.point2) AS loc2, " +
//                        "ld.line_geom " +
//                        "FROM line_data ld, points p " +
//                        ") " +
//                        "SELECT " +
//                        "ST_Length( " +
//                        "ST_Transform( " +
//                        "ST_LineSubstring(line_geom, LEAST(loc1, loc2), GREATEST(loc1, loc2)), " +
//                        "3857 " +
//                        ") " +
//                        ") AS segment_length_meters " +
//                        "FROM line_info;";
//
//        Map<String, Object> length = pool2DataSourceUtil.NpgNormal_GetListDicNo1(sql);
//        return length;
//    }
//
//
//}
